<html>
  <head></head>
  <body>
    <script src="https://raw.githubusercontent.com/craftyjs/Crafty-Distro/nightlies/crafty.js"></script>
    <script src="https://raw.githubusercontent.com/craftyjs/demos/master/devDemos/isometric/iso-engine.js"></script>
    <script>
    Crafty.init();
    Crafty.background('gray');

    Crafty.sprite(32, 32, "https://raw.githubusercontent.com/craftyjs/demos/master/devDemos/isometric/blank_32x32.png", {
        blankBox: [0,0,1,1]
    });

    Crafty.sprite(32, 16, "https://raw.githubusercontent.com/craftyjs/demos/master/devDemos/isometric/blank_32x16.png", {
        blankPlane: [0,0,1,1]
    });

    Crafty.sprite(128, 64, "https://raw.githubusercontent.com/craftyjs/demos/master/devDemos/isometric/iso-sprites.png", {
        block: [0,0,1,2],
        player: [1,0,1,2],
        tower: [2,0,1,4],
        big: [0,2,2,3],
        plane: [2,4,1,1]
    });

    // TILSESIZE
    var size = 16;
    // MAPSIZE
    var mapSize = 10;

    // MAIN TILE MAP
    var map = []; // 4x4
    for (var i = 0; i < mapSize; i++) {
        map[i] = [];
        for (var j = 0; j < mapSize; j++) {
            map[i][j] = {d: 0, c: "GridTile", i: "DOM, blankPlane"};
        }
    }
    var mapEntity = Crafty.isometric.placeTileMap(size, map);


    // PLAYER / CAMERA
    var moveZ = function(e) {
        if (e.key === Crafty.keys.SPACE)
            this.z += size;
        else if (e.key === Crafty.keys.CTRL)
            this.z -= size;
    };
    var playerEntity = Crafty.e("2D, Multiway, Collision3D, Isometric, CameraTile")
        .attr({ x: 0 * size, y: 0 * size, z: 0 * size,
                w: 1 * size, h: 1 * size, d: 1 * size })
        .multiway(200, {
            UP_ARROW: -135, W: -135,
            DOWN_ARROW: 45, S: 45,
            RIGHT_ARROW: -45, D: -45,
            LEFT_ARROW: 135, A: 135
        })
        .bind("KeyDown", moveZ)
        .bind("EntityStartDrag", function() {
            this.unbind("KeyDown", moveZ);
        })
        .bind("EntityStopDrag", function() {
            this.uniqueBind("KeyDown", moveZ);
        })
        .isometric();
    mapEntity.attach(playerEntity);



    // USER TILES
    var userTiles = {};
    var despawnTile = function(x, y, z) {
        var hash = '[' + x + '][' + y + '][' + z + ']';

        var oldTile = userTiles[hash];
        if (oldTile) oldTile.destroy();
        delete userTiles[hash];
    };
    var spawnTile = function(x, y, z, size) {
        var hash = '[' + x + '][' + y + '][' + z + ']';

        var newTile = Crafty.isometric.placeTile(size, { x: x, y: y, z: z, c: "UserTile",
            i: "DOM, blankBox, IsometricTileDraggable, IsometricTileAreaMap, IsometricTileRemove, IsometricTileSpawn"
        });
        mapEntity.attach(newTile);
        userTiles[hash] = newTile;

        return newTile;
    };
    var moveTile = function(oldX, oldY, oldZ, newX, newY, newZ) {
        var oldHash = '[' + oldX + '][' + oldY + '][' + oldZ + ']',
            newHash = '[' + newX + '][' + newY + '][' + newZ + ']';
        var tile = userTiles[oldHash];
        if (tile) userTiles[newHash] = tile;
        delete userTiles[oldHash];
    };

    Crafty.c("IsometricTileRemove", {
        init: function() {
            this.requires("Mouse");
            this.bind("MouseDown", function(e) {
                if (e.mouseButton === Crafty.mouseButtons.RIGHT) {
                    var ctrl = this._isoController;
                    var tileI = ctrl._x / size,
                        tileJ = ctrl._y / size,
                        tileK = ctrl._z / size;

                    despawnTile(tileI, tileJ, tileK);
                }
            });
        }
    });
    Crafty.c("IsometricTileSpawn", {
        init: function() {
            this.requires("IsometricTileDraggable");
            this.bind("StopDrag", function(e) {
                var ctrl = this._isoController;
                var diffX = this._x - this._oldX,
                    diffY = this._y - this._oldY;
                var tileI = ctrl._x / size,
                    tileJ = ctrl._y / size,
                    tileK = ctrl._z / size,
                    spawnK = playerEntity._z / size;

                console.log("You clicked tile at [" + tileI + "][" + tileJ + "][" + tileK + "]");
                if ((diffX === 0 || diffY === 0) && e.mouseButton === Crafty.mouseButtons.LEFT) {
                    despawnTile(tileI, tileJ, spawnK);
                    spawnTile(tileI, tileJ, spawnK, size);
                }
            });
        }
    });



    // BACKGROUND ENTITY
    var backdrop = Crafty.e("2D, Mouse").attr({
            x: -window.innerWidth/2, y: -window.innerHeight/2,
            w: window.innerWidth, h: window.innerHeight,
            z: -1e9
        })
        .bind("Click", function(e) {
            var realX = e.realX / 2 + e.realY - size / 2,
                realY = e.realY - e.realX / 2 - size / 2;
            var tileI = Math.round(realX / size),
                tileJ = Math.round(realY / size),
                spawnK = playerEntity._z / size;

            console.log("You clicked backdrop at [" + tileI + "][" + tileJ + "]");
            despawnTile(tileI, tileJ, spawnK);
            spawnTile(tileI, tileJ, spawnK, size);
        });
    playerEntity._isoDisplay.attach(backdrop);



    // Z-level display
    var zDisplay = Crafty.e("2D, DOM, Text")
        .attr({ x: 300, w: 100, z:1e9})
        .text('z-level: ' + playerEntity._z / size)
        .textFont({ size: '20px', weight: 'bold' })
        .textColor("red")
        .unselectable();
    playerEntity._isoDisplay.attach(zDisplay);
    playerEntity.bind("reorder", function() {
        zDisplay.text('z-level: ' + this._z / size);
    });


    // VIEWPORT
    Crafty.viewport.clampToEntities = false;
    Crafty.viewport.centerOn(playerEntity._isoDisplay);
    Crafty.viewport.follow(playerEntity._isoDisplay);


    // VIEWPORT TRANSFORMATIONS
    var keyRotations = {};
    keyRotations[Crafty.keys.NUMPAD_4] = 90;
    keyRotations[Crafty.keys.NUMPAD_8] = 0,
    keyRotations[Crafty.keys.NUMPAD_6] = -90,
    keyRotations[Crafty.keys.NUMPAD_2] = -180
    mapEntity.bind("KeyDown", function(e) {
        var rotation = keyRotations[e.key];
        if (typeof rotation !== "undefined") {
            this.rotation = rotation;
        }
    }).bind("MouseWheelScroll", function(evt) {
        Crafty.viewport.scale(Crafty.viewport._scale * (1 + evt.direction * 0.1));
    });
    </script>
  </body>
</html>
